#include "systemInfo.hpp"

std::string SystemInfo::getSystemName()
{
    
    if(SystemName.length()==0)
    {
        utsname sysNameInfo;
        if(uname(&sysNameInfo)==0)
        {
            SystemName=sysNameInfo.nodename;
        }
    }
    return SystemName;
}

std::string SystemInfo::getSystemVersion()
{
    if(SystemName.length()==0)
    {
        utsname sysInfo;
        if(uname(&sysInfo)==0)
        {
            SystemVersion=sysInfo.version;
        }
    }
    return SystemName;
}


struct CPUInfo
{
    double user;  
    double nice;
    double system;
    double idle;
    double iowait;
    double irq;
    double softirq;
    double steal;
    double guest;
    double guest_nice;
};


double SystemInfo::getCPUusage()
{
    std::ifstream iFile("/proc/stat");
    if(!iFile.is_open())
    {
        OATPP_LOGE("SystemInfo","Can't open file : /proc/stat");
        return 100;
    }
    std::string getItem;
    iFile>>getItem;
    if(getItem!="cpu")
    {
        OATPP_LOGE("SystemInfo","At /proc/stat, Fist line value not 'cpu' ");
        return 100;
    }
    CPUInfo cpuInfo;
    iFile>>cpuInfo.user;
    iFile>>cpuInfo.nice;
    iFile>>cpuInfo.system;
    iFile>>cpuInfo.idle;
    iFile>>cpuInfo.iowait;
    iFile>>cpuInfo.irq;
    iFile>>cpuInfo.softirq;
    iFile>>cpuInfo.steal;
    iFile>>cpuInfo.guest;
    iFile>>cpuInfo.guest_nice;
    if(!iFile.good())
    {
        OATPP_LOGE("SystemInfo","At /proc/stat, Read file not good ");
        return 100;
    }
    iFile.close();
    //Average idle time (%) = (idle * 100) / (user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice)
    return 100-(cpuInfo.idle*100)/(cpuInfo.user + cpuInfo.nice + cpuInfo.system + cpuInfo.idle + cpuInfo.iowait + cpuInfo.irq + cpuInfo.softirq + cpuInfo.steal + cpuInfo.guest + cpuInfo.guest_nice);
}

struct MemoryInfo
{
    double MemTotal;
    double MenFree;
};


double SystemInfo::getMemoryUsage()
{
    std::ifstream iFile("/proc/meminfo");
    if(!iFile.is_open())
    {
        OATPP_LOGE("SystemInfo","Can't open file : /proc/meminfo");
        return 100;
    }
    std::string itemTitle;
    iFile>>itemTitle;
    if(itemTitle!="MemTotal:")
    {
        OATPP_LOGE("SystemInfo","At /proc/memory, Fist line value not 'MemTotal:' ");
        return 100;       
    }
    MemoryInfo memoryInfo;
    iFile>>memoryInfo.MemTotal;
    iFile>>itemTitle;
    iFile>>itemTitle;
    if(itemTitle!="MemFree:")
    {
        OATPP_LOGE("SystemInfo","At /proc/memory, Fist line value not 'MemFree:' ");
        return 100;       
    }
    iFile>>memoryInfo.MenFree;
    if(!iFile.good())
    {
        OATPP_LOGE("SystemInfo","At /proc/memory, Read file not good ");
        return 100;
    }
    iFile.close();
    return 100-(memoryInfo.MenFree/memoryInfo.MemTotal*100);
}

std::string get_cur_executable_path_()
{
    char *p = NULL;
    const int len = 256;
    /// to keep the absolute path of executable's path
    char arr_tmp[len] = {0};
    readlink("/proc/self/exe", arr_tmp, len);
    if (NULL != (p = std::strrchr(arr_tmp,'/')))
        *p = '\0';
    else
    {
        OATPP_LOGE("SystemInfo","Can't get exe path : %s",arr_tmp);
        std::string("");
    }

    return std::string(arr_tmp);
}

double SystemInfo::getDiskUsage()
{
    std::string exec_str = get_cur_executable_path_();
    struct statfs diskInfo;
	statfs(exec_str.c_str(), &diskInfo);

    return (long double)diskInfo.f_bfree/diskInfo.f_blocks*100;
}

long SystemInfo::getUptime()
{
    std::ifstream iFile("/proc/uptime");
    if(!iFile.is_open())
    {
        OATPP_LOGE("SystemInfo","Can't open file : /proc/uptime");
        return 0;
    }
    long double uptime;
    iFile>>uptime;
    iFile.close();
    return uptime;
}